ObjReader = class()

function ObjReader:init(calcNormal)
    self.vList = {}
    self.uvList = {}
    self.vnList = {}
    
    self.groups = {}
    
    self.vertices = {}
    self.texCoords = {}
    self.normals = {}
    self.point = 1
    
    self.calcNormal = calcNormal or false
end

function ObjReader:readLine(text)
    local strp = ObjReader.StrSplit
    local insert = table.insert
    
    if string.len(text) == 0 then
        return
    end
    local t = strp(text," ")
    if #t < 1 then
        return
    end
    
    local first = t[1]
    if first == "#" then
        return
    elseif first == "v" then
        insert(self.vList,vec3(tonumber(t[2]),tonumber(t[3]),tonumber(t[4])))
    elseif first == "vt" then
        insert(self.uvList,vec2(tonumber(t[2]),tonumber(t[3])))
    elseif first == "vn" then
        insert(self.vnList,vec3(tonumber(t[2]),tonumber(t[3]),tonumber(t[4])))
    elseif first == "f" then
        self:operatorFace(t)
    end
end

function ObjReader:operatorFace(facelist)
    local ps = {}
    for i = 2,#facelist do
        if #facelist[i] > 0 then
            ps[i - 1] = self:operatorFaceNum(facelist[i])
        end
    end
    
    if #facelist > 4 then
        self:operatePolygon(ps)
    else
        local insert = table.insert
        for i = 1,3 do
            insert(self.vertices,ps[i][1])
        end
        if ps[1][2] then
            for i = 1,3 do
                insert(self.texCoords,ps[i][2])
            end
        end
        if ps[1][3] then
            for i = 1,3 do
                insert(self.normals,ps[i][3])
            end
        elseif self.calcNormal then
            local n = (ps[2][1] - ps[1][1]):cross(ps[3][1] - ps[1][1])
            insert(self.normals,n)
            insert(self.normals,n)
            insert(self.normals,n)
        end
    end
end

function ObjReader:operatorFaceNum(numText)
    local t = ObjReader.StrSplit(numText,"/")
    t[1] = self.vList[tonumber(t[1])]
    if t[2] and #t[2] > 0 then
        t[2] = self.uvList[tonumber(t[2])]
    else
        t[2] = nil
    end
    if t[3] then
        t[3] = self.vnList[tonumber(t[3])]
    else
        t[3] = nil
    end
    return t
end

function ObjReader:operatePolygon(ps)
    local start = ps[1]
    local insert = table.insert
    local p1,p2
    for i = 2,#ps - 1 do
        p1 = ps[i]
        p2 = ps[i + 1]
        insert(self.vertices,start[1])
        insert(self.vertices,p1[1])
        insert(self.vertices,p2[1])
    end
    if start[2] then
        for i = 2,#ps - 1 do
            p1 = ps[i]
            p2 = ps[i + 1]
            insert(self.texCoords,start[2])
            insert(self.texCoords,p1[2])
            insert(self.texCoords,p2[2])
        end
    end
    if start[3] then
        for i = 2,#ps - 1 do
            p1 = ps[i]
            p2 = ps[i + 1]
            insert(self.normals,start[3])
            insert(self.normals,p1[3])
            insert(self.normals,p2[3])
        end
    elseif self.calcNormal then
        start = start[1]
        for i = 2,#ps - 1 do
            p1 = ps[i][1] - start
            p2 = ps[i + 1][1] - start
            p1 = p1:cross(p2)
            insert(self.normals,p1)
            insert(self.normals,p1)
            insert(self.normals,p1)
        end
    end
end

function ObjReader:readAll(text)
    local lines = ObjReader.StrSplit(text,"\n")
    for _,line in ipairs(lines) do
        self:readLine(line)
    end
end

function ObjReader:readObj(objName)
    
end

function ObjReader:genMesh()
    local m = mesh()
    m.vertices = self.vertices
    m.texCoords = self.texCoords
    m.normals = self.normals
    m:setColors(255,255,255,255)
    return m
end

function ObjReader.StrSplit(l,c)
    local newlist = {}
    local strl = l
    local findLine
    
    while (true) do
        findLine = string.find (strl,c)
        if not findLine then
            table.insert(newlist,strl)
            return newlist
        end
        local strf = string.sub(strl,1,findLine - 1)
        table.insert(newlist,strf)
        strl = string.sub(strl,findLine + 1)
    end
    return newlist
end